package cn.xydpeng.springframework.beans.factory.support;

import cn.xydpeng.springframework.beans.BeansException;
import cn.xydpeng.springframework.beans.factory.BeanFactory;
import cn.xydpeng.springframework.beans.factory.BeanFactoryUtils;
import cn.xydpeng.springframework.beans.factory.FactoryBean;
import cn.xydpeng.springframework.beans.factory.config.BeanDefinition;
import cn.xydpeng.springframework.beans.factory.config.BeanPostProcessor;
import cn.xydpeng.springframework.beans.factory.config.ConfigurableBeanFactory;
import cn.xydpeng.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import cn.xydpeng.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import cn.xydpeng.springframework.lang.Nullable;
import cn.xydpeng.springframework.util.Assert;
import cn.xydpeng.springframework.util.ClassUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author xydpeng
 * @version v1.0
 * @date: 2022/10/12
 * @description:
 */
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
    /**
     * Map from bean name to merged RootBeanDefinition.
     */
    private final Map<String, RootBeanDefinition> mergedBeanDefinitions = new ConcurrentHashMap<>(256);

    /**
     * BeanPostProcessors to apply.
     */
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
    /** Cache of pre-filtered post-processors. --- 分类缓存各种BeanPostProcessor子类型 */
    @Nullable
    private volatile BeanPostProcessorCache beanPostProcessorCache;

    @Nullable
    private BeanFactory parentBeanFactory;

    private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

    @Override
    public ClassLoader getBeanClassLoader() {
        return beanClassLoader;
    }

    @Override
    public void setBeanClassLoader(ClassLoader beanClassLoader) {
        this.beanClassLoader = beanClassLoader != null ? beanClassLoader : ClassUtils.getDefaultClassLoader();
    }

    @Override
    @Nullable
    public BeanFactory getParentBeanFactory() {
        return this.parentBeanFactory;
    }

    @Override
    public boolean containsLocalBean(String name) {
        //throw new RuntimeException("containsLocalBean method not be implemented");
        String beanName = transformedBeanName(name);
        //TODO
        return containsSingleton(beanName) || containsBeanDefinition(beanName);
    }

    @Override
    public Object getBean(String name) throws BeansException {
        return doGetBean(name, null, null, false);
    }

    @Override
    public Object getBean(String name, Object... args) throws BeansException {
        return doGetBean(name, null, args, false);
    }

    @Override
    public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
        return doGetBean(name, requiredType, null, false);
    }

    protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
        //1.提取对应的beanName：解决别名alias、factoryBean名称差异
        String beanName = transformedBeanName(name);
        Object beanInstance;
        //2. Eagerly check singleton cache for manually registered singletons.
        //  ---- 尝试从DefaultSingletonBeanRegistry的三级缓存中分别查找bean，普通单例bean首次getBean时缓存查不到
        Object sharedInstance = getSingleton(beanName);
        if (sharedInstance != null && args == null) {
            //3. 上面缓存中获取到已初始化完成的普通单例bean，或者是FactoryBean对象本身"&",getObjectForBeanInstance会处理FactoryBean的情形，
            //   并把FactoryBean.getObject生成的bean放入缓存FactoryBeanRegistrySupport.factoryBeanObjectCache
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);

        } else {
            //4. Create bean instance. --- 缓存中未获取到bean,准备创建bean
            RootBeanDefinition mbd = (RootBeanDefinition) getBeanDefinition(beanName);

            // Guarantee initialization of beans that the current bean depends on.  --- 优先实例化显式指定的DependsOn依赖
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {}

            //5.不同scope模式不同处理, 开始createBean
            if (mbd.isSingleton()) {
                //创建bean 并放入一级缓存DefaultSingletonBeanRegistry.singletonObjects，并清除二三级缓存
                sharedInstance = getSingleton(beanName, () -> {
                    return createBean(beanName, mbd, args);
                });
                //到此时普通的bean已经创建并初始化完毕，FactoryBean对象本身"&"也创建完毕
                beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);

            }else if(mbd.isPrototype()){
                Object prototypeInstance = null;
                prototypeInstance = createBean(beanName, mbd, args);
                //需要处理FactoryBean的情形
                beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
            }else{
                //其他scope，先不管
            }

            beanInstance = createBean(beanName, mbd, args);
        }

        return (T) beanInstance;
    }

    /**
     *Get the object for the given bean beanInstance, either the bean
     * beanInstance itself or its created object in case of a FactoryBean.
     * 获取给定bean实例对象,实例本身或其创建的对象（如果是FactoryBean）
     * @param beanInstance
     * @param name     the name that may include factory dereference prefix
     * @param beanName
     * @param mbd
     * @return
     */
    protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
        //1. name是以"&"开头，只是获取FactoryBean对象本身
        if (BeanFactoryUtils.isFactoryDereference(name)) {
            if (!(beanInstance instanceof FactoryBean)) {
                throw new BeansException("beanInstance is not FactoryBean: " + beanInstance);
            }
            //标记一下
            if (mbd != null) {
                mbd.isFactoryBean = true;
            }
            return beanInstance;
        }
        //只是普通对象
        if (!(beanInstance instanceof FactoryBean<?> factoryBean)) {
            return beanInstance;
        }

        Object object = null;
        if (mbd != null) {
            mbd.isFactoryBean = true;
        }else {
            //取缓存FactoryBeanRegistrySupport.factoryBeanObjectCache
            object = getCachedObjectForFactoryBean(beanName);
        }
        if(object==null){

            //缓存中没有 或者入参传入有mbd，调用FactoryBean.getObject()生成对象并放入缓存
            object = getObjectFromFactoryBean(factoryBean,beanName,true);
        }
        return object;
    }


    @Override
    public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
        Assert.notNull(beanPostProcessor, "BeanPostProcessor must not be null");
        // Remove from old position, if any
        this.beanPostProcessors.remove(beanPostProcessor);
        // Add to end of list
        this.beanPostProcessors.add(beanPostProcessor);
    }

    public List<BeanPostProcessor> getBeanPostProcessors() {
        return beanPostProcessors;
    }

    protected abstract BeanDefinition getBeanDefinition(String beanName) throws BeansException;
    protected abstract boolean containsBeanDefinition(String beanName);

    protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeansException;

    /**
     * 注册实现了 DisposableBean 接口的 Bean 对象
     *
     * @param beanName
     * @param bean     实例bean
     * @param mbd
     */
    protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
        if (mbd.isSingleton()) {
            registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, mbd));
        }
        //TODO 还有其他scope类型的bean
    }

    /**
     * Return the bean name, stripping out the factory dereference prefix if necessary,
     *
     * @param name
     * @return
     */
    protected String transformedBeanName(String name) {
        return BeanFactoryUtils.transformedBeanName(name);
        //TODO 别名
    }


    protected boolean hasInstantiationAwareBeanPostProcessors() {
        return !getBeanPostProcessorCache().instantiationAware.isEmpty();
    }


    /**
     * 细分BeanPostProcessor类型，分类缓存
     * @return
     */
    BeanPostProcessorCache getBeanPostProcessorCache() {
        BeanPostProcessorCache bppCache = this.beanPostProcessorCache;
        if (bppCache == null) {
            bppCache = new BeanPostProcessorCache();
            for (BeanPostProcessor bpp : this.beanPostProcessors) {
                if (bpp instanceof InstantiationAwareBeanPostProcessor ) {
                    bppCache.instantiationAware.add((InstantiationAwareBeanPostProcessor)bpp);
                    if (bpp instanceof SmartInstantiationAwareBeanPostProcessor ) {
                        bppCache.smartInstantiationAware.add((SmartInstantiationAwareBeanPostProcessor)bpp);
                    }
                }
                /*if (bpp instanceof DestructionAwareBeanPostProcessor destructionAwareBpp) {
                    bppCache.destructionAware.add(destructionAwareBpp);
                }
                if (bpp instanceof MergedBeanDefinitionPostProcessor mergedBeanDefBpp) {
                    bppCache.mergedDefinition.add(mergedBeanDefBpp);
                }*/
            }
            this.beanPostProcessorCache = bppCache;
        }
        return bppCache;
    }



    /**
     * Internal cache of pre-filtered post-processors.  --- 用于归类存储各种BeanPostProcessor子类型
     * @since 5.3
     */
    static class BeanPostProcessorCache {
        //实例化bean的BeanPostProcessor，会在doCreateBean()之前执行
        final List<InstantiationAwareBeanPostProcessor> instantiationAware = new ArrayList<>();
        final List<SmartInstantiationAwareBeanPostProcessor> smartInstantiationAware = new ArrayList<>();
        //TODO 暂未用到的子类型
        //final List<DestructionAwareBeanPostProcessor> destructionAware = new ArrayList<>();
        //final List<MergedBeanDefinitionPostProcessor> mergedDefinition = new ArrayList<>();
    }


    /**
     * Return a merged RootBeanDefinition, traversing the parent bean definition
     * if the specified bean corresponds to a child bean definition.
     * @param beanName the name of the bean to retrieve the merged definition for
     * @return a (potentially merged) RootBeanDefinition for the given bean
     * @throws NoSuchBeanDefinitionException if there is no bean with the given name
     * @throws BeanDefinitionStoreException in case of an invalid bean definition
     */
    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
        //TODO 暂未实现MergedLocalBeanDefinition功能
        return (RootBeanDefinition)getBeanDefinition(beanName);
    }

    @Override
    public boolean isFactoryBean(String name) throws BeansException {
        String beanName = transformedBeanName(name);
        Object beanInstance = getSingleton(beanName, false);
        if (beanInstance != null) {
            return (beanInstance instanceof FactoryBean);
        }
        // No singleton instance found -> check bean definition.
        if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory cbf) {
            // No bean definition found in this factory -> delegate to parent.
            return cbf.isFactoryBean(name);
        }
        return isFactoryBean(beanName, getMergedLocalBeanDefinition(beanName));
    }

    /**
     * Check whether the given bean is defined as a {@link FactoryBean}.
     * @param beanName the name of the bean
     * @param mbd the corresponding bean definition
     */
    protected boolean isFactoryBean(String beanName, RootBeanDefinition mbd) {
        Boolean result = mbd.isFactoryBean;
        if (result == null) {
            //TODO 此处为简化实现
            Class<?> beanType = mbd.getBeanClass();
            result = (beanType != null && FactoryBean.class.isAssignableFrom(beanType));
            mbd.isFactoryBean = result;
        }
        return result;
    }



}
